<template>
    <div class="spark-desk-container">
        <aside>
            <el-button class="new-dialogue-button" type="primary" plain size="large"
                @click="createNewDialogue">新建对话</el-button>
            <div class="title">历史对话</div>
            <div class="item-box" v-loading="historyLoading">
                <dialogue-item v-for="item in historyList" :key="item.id" :data="item" :active-id="activeId"
                    @click.native="dialogueClick(item)" @getDialogueData="refreshHistoryData">
                </dialogue-item>
            </div>
        </aside>
        <article v-loading="questionLoading" element-loading-background="rgba(255, 255, 255, .3)">
            <div class="dialog-big-box">
                <div class="dialogue-box" ref="dialogueBoxSpark">
                    <div v-if="questionsDataSpark.length === 0" class="no-data-box">
                        <img src="@/assets/bg/logo.png" alt="">
                        <div class="no-data-box-text">您好，我是星火认知大模型</div>
                    </div>
                    <div v-else>
                        <question-item v-for="(item, index) in questionsDataSpark" :key="index" :info="item" type="spark"
                            :blink="blink && index === questionsDataSpark.length - 1"></question-item>
                    </div>
                </div>
            </div>
            <div class="input-box">
                <el-input v-model="question" type="textarea" placeholder="在此输入您想了解的内容，按住Shift+Enter换行" resize="none"
                    @keyup.enter.prevent="sendQuestion">
                </el-input>
                <el-button id="send-button" type="primary" :loading="buttonLoading" @click="sendQuestion">{{ buttonText
                    }}</el-button>
                <div class="tip-text">所有内容均由人工智能模型输出，其内容的准确性和完整性无法保证，不代表我们的态度或观点。</div>
            </div>
        </article>
    </div>
</template>

<script>
import questionItem from './question-item.vue'
export default {
    name: 'chat-console',
    props: { param: Object },
    data() {
        return {
            // 地址必须填写，代表着大模型的版本号！！！！！！！！！！！！！！！！
            httpUrl: new URL("https://spark-api.xf-yun.com/v3.5/chat"),
            modelDomain: '', // V1.1-V3.5动态获取，高于以上版本手动指定
            APPID: 'xxx', // 讯飞控制台获取
            API_SECRET: 'xxxxx', // 讯飞控制台获取
            API_KEY: 'xxxxx', // 讯飞控制台获取
            questionsDataSpark: null,
            blink: false
        }
    },
    components: {
        questionItem
    },
    created: function () {
    },
    methods: {
        // 获取连接url
        getWebsocketUrl() {
            // 动态获取domain信息
            switch (this.httpUrl.pathname) {
                case "/v1.1/chat":
                    this.modelDomain = "general";
                    break;
                case "/v2.1/chat":
                    this.modelDomain = "generalv2";
                    break;
                case "/v3.1/chat":
                    this.modelDomain = "generalv3";
                    break;
                case "/v3.5/chat":
                    this.modelDomain = "generalv3.5";
                    break;
            }

            return new Promise((resolve, reject) => {
                let apiKey = this.API_KEY
                let apiSecret = this.API_SECRET

                let url = 'wss://' + this.httpUrl.host + this.httpUrl.pathname

                let host = location.host
                let date = new Date().toGMTString()
                let algorithm = 'hmac-sha256'
                let headers = 'host date request-line'
                let signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${this.httpUrl.pathname} HTTP/1.1`
                let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
                let signature = CryptoJS.enc.Base64.stringify(signatureSha)
                let authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
                let authorization = btoa(authorizationOrigin)
                url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
                resolve(url)
            })
        },
        // 连接websocket
        connectWebSocket(question) {
            this.setStatus('ttsing')
            return this.getWebsocketUrl().then(url => {
                let ttsWS
                if ('WebSocket' in window) {
                    ttsWS = new WebSocket(url)
                } else if ('MozWebSocket' in window) {
                    ttsWS = new MozWebSocket(url)
                } else {
                    alert('浏览器不支持WebSocket')
                    return
                }
                this.ttsWS = ttsWS
                ttsWS.onopen = e => {
                    this.webSocketSend(question)
                    this.questionsDataSpark.push({ role: "assistant", content: '' })
                }
                ttsWS.onmessage = e => {
                    this.result(e.data)
                }
                ttsWS.onerror = e => {
                    clearTimeout(this.playTimeout)
                    this.setStatus('error')
                    alert('WebSocket报错，请f12查看详情')
                    console.error(`详情查看：${encodeURI(url.replace('wss:', 'https:'))}`)
                }
                ttsWS.onclose = e => {
                    console.log(e)
                }
            })
        },
        // websocket发送数据
        webSocketSend(question) {
            var params = {
                "header": {
                    "app_id": this.APPID, "uid": "fd3f47e4-d"
                }, "parameter": {
                    "chat": {
                        "domain": this.modelDomain, "temperature": 0.5, "max_tokens": 1024
                    }
                }, "payload": {
                    "message": {
                        "text": question
                    }
                }
            }
            this.ttsWS.send(JSON.stringify(params))
        },
        // websocket接收数据的处理
        result(resultData) {
            let jsonData = JSON.parse(resultData)
            this.jsonData = jsonData;
            let content = jsonData.payload.choices.text[0].content
            let contentArr = content.split('')
            this.total_res = this.total_res + content
            if (jsonData.header.status === 0 || this.contentArr.length === 0) {
                this.contentArr.push(...contentArr)
                this.setContent()
            } else {
                this.contentArr.push(...contentArr)
            }
            // 提问失败
            if (jsonData.header.code !== 0) {
                alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`)
                console.error(`${jsonData.header.code}:${jsonData.header.message}`)
                return
            }
            if (jsonData.header.code === 0 && jsonData.header.status === 2) {
                this.ttsWS.close()
            }
            return this.total_res;
        },
        // 展示回答文本
        setContent() {
            let timeout = this.contentArr.length > 30 ? (700 / this.contentArr.length)
                : this.contentArr.length > 10 ? (300 / this.contentArr.length)
                    : (150 / this.contentArr.length)
            setTimeout(() => {
                this.questionsDataSpark[this.questionsDataSpark.length - 1].content += this.contentArr[0]
                this.contentArr.shift()
                if (this.contentArr.length > 0) { // 文本未显示完毕，递归调用
                    this.setContent()
                } else if (this.jsonData.header.code === 0 && this.jsonData.header.status === 2) { // 回答结束
                    this.setStatus("init")
                    if (this.historyList.findIndex(item => item.id === this.activeId) === 0 && this.historyList[0].noSave) {
                        this.insertDialogue()
                    }
                    this.insertQuestion(this.questionsDataSpark[this.questionsDataSpark.length - 1], "spark")
                }
            }, timeout)
        },
    }
}
</script>

<style scoped></style>